home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / lisp / ispell.el < prev    next >
Lisp/Scheme  |  1993-07-23  |  20KB  |  610 lines

  1. ;;; ispell.el --- this is the GNU EMACS interface to GNU ISPELL version 4.
  2.  
  3. ;;Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
  4.  
  5. ;; Keywords: wp
  6.  
  7. ;;This file is part of GNU Emacs.
  8. ;;
  9. ;;GNU Emacs is free software; you can redistribute it and/or modify
  10. ;;it under the terms of the GNU General Public License as published by
  11. ;;the Free Software Foundation; either version 2, or (at your option)
  12. ;;any later version.
  13. ;;
  14. ;;GNU Emacs is distributed in the hope that it will be useful,
  15. ;;but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ;;GNU General Public License for more details.
  18. ;;
  19. ;;You should have received a copy of the GNU General Public License
  20. ;;along with GNU Emacs; see the file COPYING.  If not, write to
  21. ;;the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23. ;;; Commentary:
  24.  
  25. ;; This package provides a graceful interface to ispell, the GNU
  26. ;; spelling checker.
  27.  
  28. ;;; Code:
  29.  
  30. (defvar ispell-have-new-look t
  31.   "Non-nil means use the `-r' option when running `look'.")
  32.  
  33. (defvar ispell-enable-tex-parser nil
  34.   "Non-nil enables experimental TeX parser in Ispell for TeX-mode buffers.")
  35.  
  36. (defvar ispell-process nil "The process running Ispell")
  37. (defvar ispell-next-message nil
  38.   "An integer: where in `*ispell*' buffer to find next message from Ispell.")
  39.  
  40. (defvar ispell-command "ispell"
  41.   "Command for running Ispell.")
  42. (defvar ispell-command-options nil
  43.   "*String (or list of strings) to pass to Ispell as command arguments.
  44. You can use this to specify the name of your private dictionary.
  45. The -S option is always passed to Ispell as the last parameter,
  46. and need not be mentioned here.")
  47.  
  48. ;Each marker in this list points to the start of a word that
  49. ;ispell thought was bad last time it did the :file command.
  50. ;Notice that if the user accepts or inserts a word into his
  51. ;private dictionary, then some "good" words will be on the list.
  52. ;We would like to deal with this by looking up the words again just before
  53. ;presenting them to the user, but that is too slow on machines
  54. ;without the select system call.  Therefore, see the variable
  55. ;ispell-recently-accepted.
  56. (defvar ispell-bad-words nil
  57.   "A list of markers reflecting the output of the Ispell `:file' command.")
  58.  
  59. ;list of words that the user has accepted, but that might still
  60. ;be on the bad-words list
  61. (defvar ispell-recently-accepted nil)
  62.  
  63. ;; Non-nil means we have started showing an alternatives window.
  64. ;; This is the window config from before then.
  65. (defvar ispell-window-configuration nil)
  66.  
  67. ;t when :dump command needed
  68. (defvar ispell-dump-needed nil)
  69.  
  70. (defun ispell-flush-bad-words ()
  71.   (while ispell-bad-words
  72.     (if (markerp (car ispell-bad-words))
  73.         (set-marker (car ispell-bad-words) nil))
  74.     (setq ispell-bad-words (cdr ispell-bad-words)))
  75.   (setq ispell-recently-accepted nil))
  76.  
  77. (defun kill-ispell ()
  78.   "Kill the Ispell process.
  79. Any changes in your private dictionary
  80. that have not already been dumped will be lost."
  81.   (interactive)
  82.   (if ispell-process
  83.       (delete-process ispell-process))
  84.   (setq ispell-process nil)
  85.   (ispell-flush-bad-words))
  86.  
  87. (put 'ispell-startup-error 'error-conditions
  88.      '(ispell-startup-error error))
  89. (put 'ispell-startup-error 'error-message
  90.      "Problem starting ispell - see buffer *ispell*")
  91.  
  92. ;; Start an ispell subprocess; check the version; and display the greeting.
  93.  
  94. (defun start-ispell ()
  95.   (message "Starting ispell ...")
  96.   (let ((buf (get-buffer "*ispell*")))
  97.     (if buf
  98.     (kill-buffer buf)))
  99.   (condition-case err
  100.       (setq ispell-process
  101.         (apply 'start-process "ispell" "*ispell*" ispell-command
  102.            (append (if (listp ispell-command-options)
  103.                    ispell-command-options
  104.                  (list ispell-command-options))
  105.                '("-S"))))
  106.     (file-error (signal 'ispell-startup-error nil)))
  107.   (process-kill-without-query ispell-process)
  108.   (buffer-disable-undo (process-buffer ispell-process))
  109.   (accept-process-output ispell-process)
  110.   (let (last-char)
  111.     (save-excursion
  112.       (set-buffer (process-buffer ispell-process))
  113.       (bury-buffer (current-buffer))
  114.       (setq last-char (- (point-max) 1))
  115.       (while (not (eq (char-after last-char) ?=))
  116.     (cond ((not (eq (process-status ispell-process) 'run))
  117.            (kill-ispell)
  118.            (signal 'ispell-startup-error nil)))
  119.     (accept-process-output ispell-process)
  120.     (setq last-char (- (point-max) 1)))
  121.       (goto-char (point-min))
  122.       (let ((greeting (read (current-buffer))))
  123.     (if (not (= (car greeting) 1))
  124.         (error "Bad ispell version: wanted 1, got %d" (car greeting)))
  125.     (message (car (cdr greeting))))
  126.       (delete-region (point-min) last-char))))
  127.   
  128. ;; Make sure ispell is ready for a command.
  129. ;; Leaves buffer set to *ispell*, point at '='.
  130.  
  131. (defun ispell-sync (intr)
  132.   (if (or (null ispell-process)
  133.       (not (eq (process-status ispell-process) 'run)))
  134.       (start-ispell))
  135.   (if intr
  136.       (interrupt-process ispell-process))
  137.   (let (last-char)
  138.     (set-buffer (process-buffer ispell-process))
  139.     (bury-buffer (current-buffer))
  140.     (setq last-char (- (point-max) 1))
  141.     (while (not (eq (char-after last-char) ?=))
  142.       (accept-process-output ispell-process)
  143.       (setq last-char (- (point-max) 1)))
  144.     (goto-char last-char)))
  145.  
  146. ;; Send a command to ispell.  Choices are:
  147. ;; 
  148. ;; WORD        Check spelling of WORD.  Result is
  149. ;; 
  150. ;;             nil               not found
  151. ;;             t               spelled ok
  152. ;;             list of strings           near misses
  153. ;; 
  154. ;; :file FILENAME    scan the named file, and print the file offsets of
  155. ;;         any misspelled words
  156. ;; 
  157. ;; :insert WORD    put word in private dictionary
  158. ;; 
  159. ;; :accept WORD    don't complain about word any more this session
  160. ;; 
  161. ;; :dump        write out the current private dictionary, if necessary.
  162. ;; 
  163. ;; :reload        reread `~/ispell.words'
  164. ;; 
  165. ;; :tex
  166. ;; :troff
  167. ;; :generic    set type of parser to use when scanning whole files
  168.  
  169. (defun ispell-cmd (&rest strings)
  170.   (save-excursion
  171.     (ispell-sync t)
  172.     (set-buffer (process-buffer ispell-process))
  173.     (bury-buffer (current-buffer))
  174.     (erase-buffer)
  175.     (setq ispell-next-message (point-min))
  176.     (while strings
  177.       (process-send-string ispell-process (car strings))
  178.       (setq strings (cdr strings)))
  179.     (process-send-string ispell-process "\n")
  180.     (accept-process-output ispell-process)
  181.     (ispell-sync nil)))
  182.  
  183. (defun ispell-dump ()
  184.   (cond (ispell-dump-needed
  185.      (setq ispell-dump-needed nil)
  186.      (ispell-cmd ":dump"))))
  187.  
  188. (defun ispell-insert (word)
  189.   (ispell-cmd ":insert " word)
  190.   (if ispell-bad-words
  191.       (setq ispell-recently-accepted (cons word ispell-recently-accepted)))
  192.   (setq ispell-dump-needed t))
  193.  
  194. (defun ispell-accept (word)
  195.   (ispell-cmd ":accept " word)
  196.   (if ispell-bad-words
  197.       (setq ispell-recently-accepted (cons word ispell-recently-accepted))))
  198.  
  199. ;; Return the next message sent by the Ispell subprocess.
  200.  
  201. (defun ispell-next-message ()
  202.   (save-excursion
  203.     (set-buffer (process-buffer ispell-process))
  204.     (bury-buffer (current-buffer))
  205.     (save-restriction
  206.       (goto-char ispell-next-message)
  207.       (narrow-to-region (point)
  208.                         (progn (forward-sexp 1) (point)))
  209.       (setq ispell-next-message (point))
  210.       (goto-char (point-min))
  211.       (read (current-buffer)))))
  212.  
  213. (defun ispell-tex-buffer-p ()
  214.   (memq major-mode '(plain-TeX-mode LaTeX-mode)))
  215.  
  216. (defvar ispell-menu-map (make-sparse-keymap "Spell"))
  217. (defalias 'ispell-menu-map ispell-menu-map)
  218.  
  219. (define-key ispell-menu-map [reload-ispell]
  220.   '("Reload Dictionary" . reload-ispell))
  221.  
  222. (define-key ispell-menu-map [ispell-next]
  223.   '("Continue Check" . ispell-next))
  224.  
  225. (define-key ispell-menu-map [ispell-region]
  226.   '("Check Region" . ispell-region))
  227.  
  228. (define-key ispell-menu-map [ispell-buffer]
  229.   '("Check Buffer" . ispell))
  230.  
  231. (define-key ispell-menu-map [ispell-word]
  232.   '("Check Word" . ispell-word))
  233.  
  234. ;;;###autoload
  235. (defun ispell (&optional buf start end)
  236.   "Run Ispell over current buffer's visited file.
  237. First the file is scanned for misspelled words, then Ispell
  238. enters a loop with the following commands for every misspelled word:
  239.  
  240. DIGIT    Near miss selector.  If the misspelled word is close to
  241.     some words in the dictionary, they are offered as near misses.
  242. r    Replace.  Replace the word with a string you type.  Each word
  243.     of your new string is also checked.
  244. i    Insert.  Insert this word in your private dictionary (kept in
  245.     `$HOME/ispell.words').
  246. a    Accept.  Accept this word for the rest of this editing session,
  247.      but don't put it in your private dictionary.
  248. l    Lookup.  Look for a word in the dictionary by fast binary
  249.     search, or search for a regular expression in the dictionary
  250.     using grep.
  251. SPACE    Accept the word this time, but complain if it is seen again.
  252. q, \\[keyboard-quit]    Leave the command loop.  You can come back later with \\[ispell-next]."
  253.   (interactive)
  254.   (if (null start)
  255.       (setq start 0))
  256.   (if (null end)
  257.       (setq end 0))
  258.  
  259.   (if (null buf)
  260.       (setq buf (current-buffer)))
  261.   (setq buf (get-buffer buf))
  262.   (if (null buf)
  263.       (error "Can't find buffer"))
  264.   ;; Deactivate the mark, because we'll do it anyway if we change something,
  265.   ;; and a region highlight while in the Ispell loop is distracting.
  266.   (deactivate-mark)
  267.   (save-excursion
  268.     (set-buffer buf)
  269.     (let ((filename buffer-file-name)
  270.       (delete-temp nil))
  271.       (unwind-protect
  272.       (progn
  273.         (cond ((null filename)
  274.            (setq filename (make-temp-name "/usr/tmp/ispell"))
  275.            (setq delete-temp t)
  276.            (write-region (point-min) (point-max) filename))
  277.           ((and (buffer-modified-p buf)
  278.             (y-or-n-p (format "Save file %s? " filename)))
  279.            (save-buffer)))
  280.         (message "Ispell scanning file...")
  281.         (if (and ispell-enable-tex-parser
  282.              (ispell-tex-buffer-p))
  283.         (ispell-cmd ":tex")
  284.           (ispell-cmd ":generic"))
  285.         (ispell-cmd (format ":file %s %d %d" filename start end)))
  286.     (if delete-temp
  287.         (condition-case ()
  288.         (delete-file filename)
  289.           (file-error nil)))))
  290.     (message "Parsing ispell output ...")
  291.     (ispell-flush-bad-words)
  292.     (let (pos bad-words)
  293.       (while (numberp (setq pos (ispell-next-message)))
  294.     ;;ispell may check the words on the line following the end
  295.     ;;of the region - therefore, don't record anything out of range
  296.     (if (or (= end 0)
  297.         (< pos end))
  298.         (setq bad-words (cons (set-marker (make-marker) (+ pos 1))
  299.                   bad-words))))
  300.       (setq bad-words (cons pos bad-words))
  301.       (setq ispell-bad-words (nreverse bad-words))))
  302.   (cond ((not (markerp (car ispell-bad-words)))
  303.      (setq ispell-bad-words nil)
  304.      (message "No misspellings."))
  305.     (t
  306.      (message "Ispell parsing done.")
  307.      (ispell-next))))
  308.  
  309. ;;;###autoload
  310. (defalias 'ispell-buffer 'ispell)
  311.  
  312. (defun ispell-next ()
  313.   "Resume command loop for most recent Ispell command."
  314.   (interactive)
  315.   (setq ispell-window-configuration nil)
  316.   (unwind-protect
  317.       (catch 'quit
  318.     ;; There used to be a save-excursion here,
  319.     ;; but that was annoying: it's better if point doesn't move
  320.     ;; when you type q.
  321.     (let (next)
  322.       (while (markerp (setq next (car ispell-bad-words)))
  323.         (switch-to-buffer (marker-buffer next))
  324.         (push-mark)
  325.         (ispell-point next "at saved position.")
  326.         (setq ispell-bad-words (cdr ispell-bad-words))
  327.         (set-marker next nil))))
  328.     (if ispell-window-configuration
  329.     (set-window-configuration ispell-window-configuration))
  330.     (cond ((null ispell-bad-words)
  331.        (error "Ispell has not yet been run."))
  332.       ((markerp (car ispell-bad-words))
  333.        (message (substitute-command-keys
  334.                        "Type \\[ispell-next] to continue.")))
  335.       ((eq (car ispell-bad-words) nil)
  336.        (setq ispell-bad-words nil)
  337.        (message "No more misspellings (but checker was interrupted.)"))
  338.       ((eq (car ispell-bad-words) t)
  339.        (setq ispell-bad-words nil)
  340.        (message "Ispell done."))
  341.       (t
  342.        (setq ispell-bad-words nil)
  343.        (message "Bad ispell internal list"))))
  344.   (ispell-dump))
  345.  
  346. ;;;###autoload
  347. (defun ispell-word (&optional resume)
  348.   "Check the spelling of the word under the cursor.
  349. See the command `ispell' for more information.
  350. With a prefix argument, resume handling of the previous Ispell command."
  351.   (interactive "P")
  352.   (if resume
  353.       (ispell-next)
  354.     (condition-case err
  355.     (catch 'quit
  356.       (save-window-excursion
  357.         (ispell-point (point) "at point."))
  358.       (ispell-dump))
  359.       (ispell-startup-error
  360.        (cond ((y-or-n-p "Problem starting ispell, use old-style spell instead? ")
  361.           (load-library "spell")
  362.           (define-key esc-map "$" 'spell-word)
  363.           (spell-word)))))))
  364. ;;;###autoload
  365. (define-key esc-map "$" 'ispell-word)
  366.  
  367. ;;;###autoload
  368. (defun ispell-region (start &optional end)
  369.   "Check the spelling for all of the words in the region."
  370.   (interactive "r")
  371.   (ispell (current-buffer) start end))
  372.  
  373. (defun ispell-letterp (c)
  374.   (and c
  375.        (or (and (>= c ?A) (<= c ?Z))
  376.        (and (>= c ?a) (<= c ?z))
  377.        (>= c 128))))
  378.  
  379. (defun ispell-letter-or-quotep (c)
  380.   (and c
  381.        (or (and (>= c ?A) (<= c ?Z))
  382.        (and (>= c ?a) (<= c ?z))
  383.        (= c ?')
  384.        (>= c 128))))
  385.  
  386. (defun ispell-find-word-start ()
  387.   ;;backward to a letter
  388.   (if (not (ispell-letterp (char-after (point))))
  389.       (while (and (not (bobp))
  390.           (not (ispell-letterp (char-after (- (point) 1)))))
  391.     (backward-char)))
  392.   ;;backward to beginning of word
  393.   (while (ispell-letter-or-quotep (char-after (- (point) 1)))
  394.     (backward-char))
  395.   (skip-chars-forward "'"))
  396.  
  397. (defun ispell-find-word-end ()
  398.   (while (ispell-letter-or-quotep (char-after (point)))
  399.     (forward-char))
  400.   (skip-chars-backward "'"))
  401.  
  402. (defun ispell-next-word ()
  403.   (while (and (not (eobp))
  404.           (not (ispell-letterp (char-after (point)))))
  405.     (forward-char)))
  406.  
  407. ;if end is nil, then do one word at start
  408. ;otherwise, do all words from the beginning of the word where
  409. ;start points, to the end of the word where end points
  410. (defun ispell-point (start message)
  411.   (let ((wend (make-marker))
  412.     rescan
  413.     end)
  414.     ;; There used to be a save-excursion here,
  415.     ;; but that was annoying: it's better if point doesn't move
  416.     ;; when you type q.
  417.     (goto-char start)
  418.     (ispell-find-word-start)        ;find correct word start
  419.     (setq start (point-marker))
  420.     (ispell-find-word-end)        ;now find correct end
  421.     (setq end (point-marker))
  422.     (if (>= start end)
  423.     (error "No word %s" message))
  424.     (while (< start end)
  425.       (goto-char start)
  426.       (ispell-find-word-end)        ;find end of current word
  427.                     ;could be before 'end' if
  428.                     ;user typed replacement
  429.                     ;that is more than one word
  430.       (set-marker wend (point))
  431.       (setq rescan nil)
  432.       (setq word (buffer-substring start wend))
  433.       (cond ((ispell-still-bad word)
  434. ;;; This just causes confusion. -- rms.
  435. ;;;         (goto-char start)
  436. ;;;         (sit-for 0)
  437.          (message (format "Ispell checking %s" word))
  438.          (ispell-cmd word)
  439.          (let ((message (ispell-next-message)))
  440.            (cond ((eq message t)
  441.               (message "%s: ok" word))
  442.              ((or (null message)
  443.               (consp message))
  444.               (setq rescan
  445.                 (ispell-command-loop word start wend message)))
  446.              (t
  447.               (error "unknown ispell response %s" message))))))
  448.       (cond ((null rescan)
  449.          (goto-char wend)
  450.          (ispell-next-word)
  451.          (set-marker start (point)))))
  452.     ;;clear the choices buffer; otherwise it's hard for the user to tell
  453.     ;;when we get back to the command loop
  454.     (let ((buf (get-buffer "*ispell choices*")))
  455.       (cond (buf
  456.          (set-buffer buf)
  457.          (erase-buffer))))
  458.     (set-marker start nil)
  459.     (set-marker end nil)
  460.     (set-marker wend nil)))
  461.   
  462. (defun ispell-still-bad (word)
  463.   (let ((words ispell-recently-accepted)
  464.     (ret t)
  465.     (case-fold-search t))
  466.     (while words
  467.       (cond ((eq (string-match (car words) word) 0)
  468.          (setq ret nil)
  469.          (setq words nil)))
  470.       (setq words (cdr words)))
  471.     ret))
  472.  
  473. (defun ispell-show-choices (word message first-line)
  474.   ;;if there is only one window on the frame, make the ispell
  475.   ;;messages winow be small.  otherwise just use the other window
  476.   (let* ((selwin (selected-window))
  477.      (resize (eq selwin (next-window)))
  478.      (buf (get-buffer-create "*ispell choices*"))
  479.      w)
  480.     (or ispell-window-configuration
  481.     (setq ispell-window-configuration (current-window-configuration)))
  482.     (setq w (display-buffer buf))
  483.     (buffer-disable-undo buf)
  484.     (if resize
  485.     (unwind-protect
  486.         (progn
  487.           (select-window w)
  488.           (enlarge-window (- 6 (window-height w))))
  489.       (select-window selwin)))
  490.     (save-excursion
  491.       (set-buffer buf)
  492.       (bury-buffer buf)
  493.       (set-window-point w (point-min))
  494.       (set-window-start w (point-min))
  495.       (erase-buffer)
  496.       (insert first-line "\n")
  497.       (insert
  498.        "SPC skip; A accept; I insert; DIGIT select; R replace; \
  499. L lookup; Q quit\n")
  500.       (cond ((not (null message))
  501.          (let ((i 0))
  502.            (while (< i 3)
  503.          (let ((j 0))
  504.            (while (< j 3)
  505.              (let* ((n (+ (* j 3) i))
  506.                 (choice (nth n message)))
  507.                (cond (choice
  508.                   (let ((str (format "%d %s" n choice)))
  509.                 (insert str)
  510.                 (insert-char ?  (- 20 (length str)))))))
  511.              (setq j (+ j 1))))
  512.          (insert "\n")
  513.          (setq i (+ i 1)))))))))
  514.  
  515. (defun ispell-command-loop (word start end message)
  516.   (let ((flag t)
  517.     (rescan nil)
  518.     first-line)
  519.     (if (null message)
  520.     (setq first-line (concat "No near misses for '" word "'"))
  521.       (setq first-line (concat "Near misses for '" word "'")))
  522.     (while flag
  523.       (ispell-show-choices word message first-line)
  524.       (message "Ispell command: ")
  525.       (undo-boundary)
  526.       (let ((c (downcase (read-char)))
  527.         replacement)
  528.     (cond ((and (>= c ?0)
  529.             (<= c ?9)
  530.             (setq replacement (nth (- c ?0) message)))
  531.            (ispell-replace start end replacement)
  532.            (setq flag nil))
  533.           ((= c ?q)
  534.            (throw 'quit nil))
  535.           ((= c ? )
  536.            (setq flag nil))
  537.           ((= c ?r)
  538.            (ispell-replace start end (read-string "Replacement: "))
  539.            (setq rescan t)
  540.            (setq flag nil))
  541.           ((= c ?i)
  542.            (ispell-insert word)
  543.            (setq flag nil))
  544.           ((= c ?a)
  545.            (ispell-accept word)
  546.            (setq flag nil))
  547.           ((= c ?l)
  548.            (let ((val (ispell-do-look word)))
  549.          (setq first-line (car val))
  550.          (setq message (cdr val))))
  551.           ((= c ??)
  552.            (message
  553.         "Type 'C-h d ispell' to the emacs main loop for more help")
  554.            (sit-for 2))
  555.           (t
  556.            (message "Bad ispell command")
  557.            (sit-for 2)))))
  558.     rescan))
  559.  
  560. (defun ispell-do-look (bad-word)
  561.   (let (regex buf words)
  562.     (cond ((null ispell-have-new-look)
  563.        (setq regex (read-string "Lookup: ")))
  564.       (t
  565.        (setq regex (read-string "Lookup (regex): " "^"))))
  566.     (setq buf (get-buffer-create "*ispell look*"))
  567.     (save-excursion
  568.       (set-buffer buf)
  569.       (delete-region (point-min) (point-max))
  570.       (if ispell-have-new-look
  571.       (call-process "look" nil buf nil "-r" regex)
  572.     (call-process "look" nil buf nil regex))
  573.       (goto-char (point-min))
  574.       (forward-line 10)
  575.       (delete-region (point) (point-max))
  576.       (goto-char (point-min))
  577.       (while (not (= (point-min) (point-max)))
  578.     (end-of-line)
  579.     (setq words (cons (buffer-substring (point-min) (point)) words))
  580.     (forward-line)
  581.     (delete-region (point-min) (point)))
  582.       (kill-buffer buf)
  583.       (cons (format "Lookup '%s'" regex)
  584.         (reverse words)))))
  585.     
  586. (defun ispell-replace (start end new)
  587.   (goto-char start)
  588.   (insert new)
  589.   (delete-region (point) end))
  590.  
  591. (defun reload-ispell ()
  592.   "Tell Ispell to re-read your private dictionary."
  593.   (interactive)
  594.   (ispell-cmd ":reload"))
  595.  
  596. (defun batch-make-ispell ()
  597.   (byte-compile-file "ispell.el")
  598.   (find-file "ispell.texinfo")
  599.   (let ((old-dir default-directory)
  600.     (default-directory "/tmp"))
  601.     (texinfo-format-buffer))
  602.   (Info-validate)
  603.   (if (get-buffer " *problems in info file*")
  604.       (kill-emacs 1))
  605.   (write-region (point-min) (point-max) "ispell.info"))
  606.  
  607. (provide 'ispell)
  608.  
  609. ;;; ispell.el ends here
  610.